package com.huilian.iotbox.admin.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.huilian.iotbox.admin.dao.MoneyWithdrawDao;
import com.huilian.iotbox.admin.service.*;
import com.huilian.iotbox.data.common.RedisKey;
import com.huilian.iotbox.data.common.ServerResponse;
import com.huilian.iotbox.data.config.AgencyConfig;
import com.huilian.iotbox.data.config.MiddlewareConfig;
import com.huilian.iotbox.data.controller.ControllerException;
import com.huilian.iotbox.data.dto.AgencyDto;
import com.huilian.iotbox.data.dto.MoneyDetailsDto;
import com.huilian.iotbox.data.dto.MoneyWithdrawDto;
import com.huilian.iotbox.data.dto.UserDto;
import com.huilian.iotbox.data.enums.*;
import com.huilian.iotbox.data.po.MoneyWithdraw;
import com.huilian.iotbox.data.po.MoneyWithdrawInvoiceInfo;
import com.huilian.iotbox.data.po.User;
import com.huilian.iotbox.data.po.UserBankCard;
import com.huilian.iotbox.data.properties.ConfigProperties;
import com.huilian.iotbox.data.service.UserBalanceService;
import com.huilian.iotbox.data.utils.HttpUtils;
import com.huilian.iotbox.data.utils.HttpsMain;
import com.huilian.iotbox.data.utils.SciCalUtils;
import com.huilian.iotbox.data.utils.Util;
import com.huilian.iotbox.data.vo.MoneyWithdrawVo;
import com.huilian.iotbox.data.vo.UserInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Serializable;
import java.math.BigDecimal;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.util.*;

/**
 * @author 谢洛涛
 * @date 2021/4/8 9:23
 */
@Service
@Slf4j
public class MoneyWithdrawServiceImpl implements MoneyWithdrawService {
    @Resource
    private MoneyWithdrawDao moneyWithdrawDao;
    @Autowired
    private UserService userService;
    @Autowired
    private AgencyService agencyService;
    @Autowired
    private UserBankCardService userBankCardService;
    @Autowired
    private MoneyWithdrawInvoiceInfoService moneyWithdrawInvoiceInfoService;
    @Autowired
    private UserBalanceService userBalanceService;
    @Autowired
    private MoneyDetailsService moneyDetailsService;
    @Resource
    private RedisTemplate<String, Serializable> redisCacheTemplate;
    @Resource
    private ConfigProperties configProperties;
    @Autowired
    private AgencyConfig agencyConfig;

    @Override
    public PageInfo findMoneyWithdrawList(MoneyWithdraw moneyWithdraw) {
        PageHelper.startPage(moneyWithdraw.getPageNum(), moneyWithdraw.getPageSize());
        PageInfo pageInfo = new PageInfo(moneyWithdrawDao.findMoneyWithdrawList(moneyWithdraw));
        return pageInfo;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public ServerResponse AddMoneyWithdraw(MoneyWithdrawDto moneyWithdrawDto) throws Exception {
        moneyWithdrawDto.setUserId(moneyWithdrawDto.getUserInfo().getId());
        // 查询用户余额
        User user = userService.findUserById(moneyWithdrawDto.getUserInfo().getId());
        if (user != null) {
            moneyWithdrawDto.setMobile(user.getMobile());
            BigDecimal balance = null;
            // 获取提现类型的余额
            if (MoneyTypeEnum.BALANCE.getCode().equals(moneyWithdrawDto.getWithdrawType())) {
                balance = user.getBalance();
            } else if (MoneyTypeEnum.COMMISSION_BALANCE.getCode().equals(moneyWithdrawDto.getWithdrawType())) {
                balance = user.getCommissionBalance();
            }
            if (moneyWithdrawDto.getMoney().compareTo(balance) > 0) {
                throw new Exception("余额不足");
            }
            BigDecimal waitInvoiceMoney = new BigDecimal("0");
            //平台扣除税点
            BigDecimal platformTax = BigDecimal.ZERO;
            //提现金额
            BigDecimal totalMoney = moneyWithdrawDto.getMoney();
            moneyWithdrawDto.setPoundage(BigDecimal.ZERO);  //手续费
            //查询用户未开发票记录,获取未开票金额
            totalMoney = totalMoney.add(waitInvoiceMoney);
            /**
             * 平台代替开发票
             */
            if ((InvoiceFlagEnum.REPLACEINVOICE.getCode()).equals(moneyWithdrawDto.getInvoiceFlag())) {
                // 判断是提现平台收款余额 或分润余额 （平台收款余额提现不需要手续费）
//                if (MoneyTypeEnum.COMMISSION_BALANCE.getCode().equals(moneyWithdrawDto.getWithdrawType())) {
                // 根据UserId查询是否是机构和机构的手续费
                AgencyDto agencyDto = agencyService.getUserAgencyByUserId(moneyWithdrawDto.getUserInfo().getId());
                if (agencyDto != null && agencyDto.getWithdrawRate() != null) {
                    platformTax = agencyDto.getWithdrawRate();
                } else {
                    platformTax = new BigDecimal("0.08");
                }
//                }
                moneyWithdrawDto.setSignInStatus(1);
            } else {
                // 判断是提现平台收款余额 或分润余额 （平台收款余额提现不需要手续费）
//                if (MoneyTypeEnum.COMMISSION_BALANCE.getCode().equals(moneyWithdrawDto.getWithdrawType())) {
                if (!("02".equals(moneyWithdrawDto.getInvoiceTaxType()))) {
                    platformTax = new BigDecimal("0.03");
                }
//                }
                moneyWithdrawDto.setSignInStatus(0);
            }
            moneyWithdrawDto.setTax(totalMoney.multiply(platformTax));
            moneyWithdrawDto.setPlatformTax(platformTax);
            //计算实际到账金额
            moneyWithdrawDto.setActualAccount(moneyWithdrawDto.getMoney().subtract(moneyWithdrawDto.getPoundage()).subtract(moneyWithdrawDto.getTax()));
            moneyWithdrawDto.setInvoiceMoney(moneyWithdrawDto.getMoney().add(waitInvoiceMoney).subtract(moneyWithdrawDto.getPoundage()).subtract(moneyWithdrawDto.getTax()));
            moneyWithdrawDto.setStatus(MoneyWithdrawStatusEnum.WAITDEALWITH.getCode());
            /**获取当前登录的机构绑定的结算卡*/
            UserBankCard userBankCard = userBankCardService.getBindUserBankCardByType(moneyWithdrawDto.getUserId(), moneyWithdrawDto.getType());
            moneyWithdrawDto.setUserName(userBankCard.getBankCertName());
            moneyWithdrawDto.setBankCardNo(userBankCard.getBankCardNo());
            moneyWithdrawDto.setBankName(userBankCard.getBankName());
            moneyWithdrawDto.setBranchName(userBankCard.getBranchName());

            //添加提现记录
            moneyWithdrawDao.addMoneyWithdraws(moneyWithdrawDto);

            if (userBankCard.getCount() != null) {
                userBankCard.setCount(userBankCard.getCount() + 1);
            } else {
                userBankCard.setCount(1);
            }
            // 添加提现次数
            userBankCardService.updateUserBankCardCount(userBankCard);
            // 扣除余额

            UserDto userDto = new UserDto();
            userDto.setId(user.getId());
            userDto.setSubtractMoney(moneyWithdrawDto.getMoney());
            userDto.setMoneyType(moneyWithdrawDto.getWithdrawType());
            User tempUser = userBalanceService.subtractBalance(userDto, 0);

            //添加资金明细记录
            MoneyDetailsDto moneyDetailsDto = new MoneyDetailsDto();
            moneyDetailsDto.setUserId(moneyWithdrawDto.getUserId());
            moneyDetailsDto.setMoney(moneyWithdrawDto.getMoney());
            moneyDetailsDto.setCashFlowType(2);
            moneyDetailsDto.setType(MoneyDetailsTypeEnum.MONEY_WITHDRAW.getCode());
            moneyDetailsDto.setVoucherNo(String.valueOf(moneyWithdrawDto.getId()));
            if (MoneyTypeEnum.BALANCE.getCode().equals(userDto.getMoneyType())) {
                moneyDetailsDto.setBalance(tempUser.getBalance());
            } else {
                moneyDetailsDto.setBalance(tempUser.getCommissionBalance());
            }
            moneyDetailsDto.setRemark("提现");
            moneyDetailsService.insert(moneyDetailsDto);
            if (InvoiceFlagEnum.OWNINVOICE.getCode().equals(moneyWithdrawDto.getInvoiceFlag())) {
                for (int i = 0; i < moneyWithdrawDto.getInvoicePhotoList().size(); i++) {
                    MoneyWithdrawInvoiceInfo invoiceInfo = new MoneyWithdrawInvoiceInfo();
                    invoiceInfo.setInvoicePhoto(moneyWithdrawDto.getInvoicePhotoList().get(i));
                    invoiceInfo.setInvoiceDate(moneyWithdrawDto.getInvoiceDate());
                    invoiceInfo.setWithdrawId(moneyWithdrawDto.getId());
                    moneyWithdrawInvoiceInfoService.insert(invoiceInfo);
                }
            }
            return ServerResponse.createBySuccess("申请成功");
        } else {
            throw new Exception("提现用户信息异常，请重试或联系管理员");
        }

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ServerResponse updateMoneyWithdraw(List<MoneyWithdrawDto> moneyWithdrawDtoList) throws Exception {
        for (MoneyWithdrawDto moneyWithdrawDto : moneyWithdrawDtoList) {
            MoneyWithdrawVo entity = moneyWithdrawDao.findMoneyWithdrawById(moneyWithdrawDto.getId());
            if (MoneyWithdrawStatusEnum.SUCCESS.getCode().equals(entity.getStatus()) || MoneyWithdrawStatusEnum.FAIL.getCode().equals(entity.getStatus())
                    || MoneyWithdrawStatusEnum.DAIFU_REMIT.getCode().equals(entity.getStatus())) {
                return ServerResponse.createByErrorMessage(entity.getUserName() + "提现已处理，请刷新页面");
            }
            /**
             *  FAIL拒绝
             */
            if (MoneyWithdrawStatusEnum.FAIL.getCode().equals(moneyWithdrawDto.getStatus())) {
                //获取用户对象
//                BigDecimal balance = null;
                User user = userService.findUserById(entity.getUserId());
                //变动后余额
                User tempUser = null;
                if (MoneyTypeEnum.BALANCE.getCode().equals(entity.getWithdrawType()) || MoneyTypeEnum.COMMISSION_BALANCE.getCode().equals(entity.getWithdrawType())) {
                    if (user != null) {
                        // 给用户加余额
                        UserDto userDto = new UserDto();
                        userDto.setId(user.getId());
                        userDto.setAddMoney(entity.getMoney());
                        userDto.setMoneyType(entity.getWithdrawType());
                        tempUser = userBalanceService.addBalance(userDto, 0);
                    } else {
                        return ServerResponse.createByErrorMessage("发生未知错误，请联系管理员");
                    }
                }
                UserBankCard userBankCard = userBankCardService.getBindUserBankCardByType(moneyWithdrawDto.getUserId(), moneyWithdrawDto.getType());
                if (userBankCard.getCount() != null) {
                    userBankCard.setCount(userBankCard.getCount() - 1);
                } else {
                    userBankCard.setCount(0);
                }
                userBankCardService.updateUserBankCardCount(userBankCard);

                MoneyDetailsDto moneyDetailsDto = new MoneyDetailsDto();
                moneyDetailsDto.setUserId(entity.getUserId());
                moneyDetailsDto.setMoney(entity.getMoney());
                moneyDetailsDto.setCashFlowType(1);
                moneyDetailsDto.setType(MoneyDetailsTypeEnum.BALANCE.getCode());
                moneyDetailsDto.setVoucherNo(String.valueOf(entity.getId()));
                if (MoneyTypeEnum.BALANCE.getCode().equals(entity.getWithdrawType())) {
                    moneyDetailsDto.setBalance(tempUser.getBalance());
                } else {
                    moneyDetailsDto.setBalance(tempUser.getCommissionBalance());
                }
                moneyDetailsDto.setRemark("提现申请拒绝");
                moneyDetailsService.insert(moneyDetailsDto);
            }
            moneyWithdrawDto.setDealTime(new Date());
            // 签收发票图片  处理提现但不会处理签收发票数据
//            moneyWithdrawDto.setSignInStatus(SignInStatusEnum.SIGN_FOR.getCode());
            moneyWithdrawDao.updateMoneyWithdraw(moneyWithdrawDto);
        }
        return ServerResponse.createBySuccessMessage("处理成功");
    }

    @Override
    public ServerResponse daiFuBalance(List<MoneyWithdrawDto> moneyWithdrawDtoList, UserInfo userInfo) throws Exception {
        for (MoneyWithdrawDto moneyWithdrawDto : moneyWithdrawDtoList) {
            //根据id获取提现记录
            MoneyWithdrawVo entity = moneyWithdrawDao.findMoneyWithdrawById(moneyWithdrawDto.getId());
            if (MoneyWithdrawStatusEnum.SUCCESS.getCode().equals(entity.getStatus()) || MoneyWithdrawStatusEnum.FAIL.getCode().equals(entity.getStatus())
                    || MoneyWithdrawStatusEnum.DAIFU_REMIT.getCode().equals(entity.getStatus())) {
                return ServerResponse.createByErrorMessage(entity.getUserName() + "提现已处理，请刷新页面");
            }
        }
        //判断验证码
        String key = RedisKey.DAIFU_SMSCODE_ + userInfo.getId();
        String s = (String) redisCacheTemplate.opsForValue().get(key);
        if (StringUtils.isEmpty(s)) {
            return ServerResponse.createByErrorMessage("验证码不存在");
        } else {
            if (!s.equals(moneyWithdrawDtoList.get(0).getSmsCode())) {
                return ServerResponse.createByErrorMessage("验证码错误");
            }
        }

        for (MoneyWithdrawDto moneyWithdraw : moneyWithdrawDtoList) {
            MoneyWithdrawVo entity = moneyWithdrawDao.findMoneyWithdrawById(moneyWithdraw.getId());
            try {
                ServerResponse response = this.addDaifuOrder(entity);
                if (OperationLogEnum.STATUS_SUCC.getCode().equals(Util.stringConvert(response.getStatus()))) {
                    String outTradeNo = (String) response.getData();
                    //代付打款中
                    moneyWithdraw.setDaifuOutTradeNo(outTradeNo);
//                    moneyWithdraw.setSignInStatus();
                    moneyWithdraw.setStatus(MoneyWithdrawStatusEnum.DAIFU_REMIT.getCode());
                    moneyWithdraw.setDealTime(new Date());
                    moneyWithdrawDao.updateMoneyWithdraw(moneyWithdraw);
                } else {
                    log.info("报错信息", response.getMsg());
                    System.out.println(response.getMsg());
                    moneyWithdraw.setStatus(MoneyWithdrawStatusEnum.DAIFU_FAIL.getCode());
                    moneyWithdraw.setRemark(response.getMsg());
                    moneyWithdraw.setDealTime(new Date());
                    moneyWithdrawDao.updateMoneyWithdraw(moneyWithdraw);
                    return ServerResponse.createByErrorMessage(response.getMsg());
                }
            } catch (Exception e) {
                return ServerResponse.createByErrorCodeMessage("代付打款错误!", e.toString());
            }
        }
        redisCacheTemplate.delete(key);
        redisCacheTemplate.delete(key + "EXPR");
        return ServerResponse.createBySuccess("代付处理中");
    }


    // 提现代付打款（先写在这边后期如果需要再移动）
    private ServerResponse addDaifuOrder(MoneyWithdrawVo moneyWithdraw) {
        Map<String, Object> daifuOrder = new HashMap<>();
        daifuOrder.put("outTradeNo", UUID.randomUUID().toString());
        daifuOrder.put("dfMerchantId", agencyConfig.getDfMerchant());
        daifuOrder.put("name", moneyWithdraw.getUserName());
        daifuOrder.put("cardNo", moneyWithdraw.getBankCardNo());
        daifuOrder.put("amount", moneyWithdraw.getActualAccount().multiply(new BigDecimal("100")));
        if (moneyWithdraw.getIdCardNo() != null) {
            daifuOrder.put("idCardNo", moneyWithdraw.getIdCardNo());
        } else {
            daifuOrder.put("idCardNo", "415284198602085495");
        }
        daifuOrder.put("summary", "代付打款");
        daifuOrder.put("purpose", "代付打款");
        daifuOrder.put("notifyUrl", configProperties.getAdminBackEndUrl() + "/api/moneyWithdraw/daiFuNotice");
        String param = HttpUtils.formatDaifu(agencyConfig, daifuOrder, FunctionEnum.DAIFU_PAY.getCode());
        String response = null;
        try {
            response = HttpsMain.httpsReq(MiddlewareConfig.daifuOrder, param);
//            response = "{\"code\":\"0000\",\"data\":{\"resultStatus\":\"S\",\"outTradeNo\":\"d1352ea9-8782-4c9e-950d-92a85864b33f\",\"function\":\"daifu.pay\",\"resultCode\":\"0000\"},\"sign\":\"S0ZuflSWWTUsFmCxk875zoy9Jr76dfFuMHbpbrUXBKgrDy/ACV6JpyGwDbwCQZgVHOIWcoUlcZCaoyvTVS/LStjwe1rEKW5AelYbn0MbJwFe6p1lJXvYQPkqiwO81FdSQPu8lC+eEdZHLYQcYeAjUvZcLFobbCAfqLx/gPuO/rLgdFpW1N4LfExfF17eyoKU39fU8O7vygg/Un8b7vaKJdPNAX0to0OQWzJHsxWG/o7sXq8bIEJl09V5KwyYNd0sXFZ3zEr3XcWBumlTYCFqAaHiX8zq15Pso/s3kF690zj3Mw/S2qcG5uNpGOFFqEkvHsgGBcvesMOXKlWOViJfxg==\",\"status\":\"S\",\"timestamp\":\"1594115863559\"}\n";
            log.info("请求响应结果{}", response);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchProviderException e) {
            e.printStackTrace();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        }
        //验签
        if (!HttpUtils.verifyResponseSign(response)) {
            throw new ControllerException("验签失败!请核实订单状态，订单号：" + daifuOrder.get("outTradeNo"));
        }
        JSONObject resultMap = JSON.parseObject(response);
        JSONObject resultData = JSON.parseObject(JSON.parseObject(response).getString("data"));

        if (RequestStatus.SUCCESS.getCode().equals(resultMap.getString("status"))
                && RequestStatus.SUCCESS_CODE.getCode().equals(resultMap.getString("code"))) {
            return ServerResponse.createBySuccess(resultData.getString("outTradeNo"));
        } else {
            return ServerResponse.createByErrorMessage(resultMap.getString("msg"));
        }
    }


    /**
     * 代付回调
     **/
    @Override
    public String daiFuNotice(HttpServletRequest request) throws Exception {
        BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream()));
        String tempLine = "";
        StringBuffer resultBuffer = new StringBuffer();
        while ((tempLine = reader.readLine()) != null) {
            resultBuffer.append(tempLine).append(System.getProperty("line.separator"));
        }
        String response = resultBuffer.toString();
        log.info("代付回调通知报文{}", response);
        MoneyWithdrawDto moneyWithdrawDto = new MoneyWithdrawDto();
        final Map<String, Object> res = HttpUtils.getResultData(response);
        Map<String, String> result = (Map<String, String>) res.get("data");
        String outTradeNo = result.get("outTradeNo");
        BigDecimal amount = SciCalUtils.sciCalToBD(new BigDecimal(result.get("amount")).divide(new BigDecimal("100")), 2);
        // 根据订单号查询提现数据
        MoneyWithdrawVo moneyWithdrawVo = moneyWithdrawDao.findMoneyWithdrawByOutTradeNo(outTradeNo, amount);
        if (RequestStatus.SUCCESS.getCode().equals(res.get("status")) && RequestStatus.SUCCESS_CODE.getCode().equals(res.get("code"))) {
            if ("00".equals(result.get("status"))) {
                moneyWithdrawDto.setId(moneyWithdrawVo.getId());
                moneyWithdrawDto.setStatus(MoneyWithdrawStatusEnum.SUCCESS.getCode());
                moneyWithdrawDto.setDealTime(new Date());
                moneyWithdrawDao.updateMoneyWithdraw(moneyWithdrawDto);
                return "SUCCESS";
            } else if ("20".equals(result.get("status"))) {
                moneyWithdrawDto.setId(moneyWithdrawVo.getId());
                moneyWithdrawDto.setStatus(MoneyWithdrawStatusEnum.DAIFU_FAIL.getCode());
                moneyWithdrawDto.setDealTime(new Date());
                moneyWithdrawDto.setRemark((String) res.get("msg"));
                moneyWithdrawDao.updateMoneyWithdraw(moneyWithdrawDto);
            }
        } else if (RequestStatus.FAILED.getCode().equals(res.get("status")) && RequestStatus.FAILED_CODE.getCode().equals(res.get("code"))) {
            if ("20".equals(result.get("status"))) {
                moneyWithdrawDto.setId(moneyWithdrawVo.getId());
                moneyWithdrawDto.setStatus(MoneyWithdrawStatusEnum.DAIFU_FAIL.getCode());
                moneyWithdrawDto.setDealTime(new Date());
                moneyWithdrawDto.setRemark((String) res.get("msg"));
                moneyWithdrawDao.updateMoneyWithdraw(moneyWithdrawDto);
            }
        }

        return "error";
    }

    @Override
    public Integer updateSignInInvoice(MoneyWithdraw moneyWithdraw) {
        MoneyWithdrawDto moneyWithdrawDto = new MoneyWithdrawDto();
        moneyWithdrawDto.setId(moneyWithdraw.getId());
        moneyWithdrawDto.setSignInStatus(moneyWithdraw.getSignInStatus());
        return moneyWithdrawDao.updateMoneyWithdraw(moneyWithdrawDto);
    }

    @Override
    public MoneyWithdrawVo findMoneyWithdrawStatistics(MoneyWithdraw moneyWithdraw) {
        return moneyWithdrawDao.findMoneyWithdrawStatistics(moneyWithdraw);
    }
}
